/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief JoystickControl module imported from GIMUI
 * \author Harri Kukkonen
 * \author Antti Maula <antti.maula@tkk.fi>
 *
 * $Id: JoystickControl.cpp,v 1.5 2009-04-23 08:30:00 amaula Exp $
 *
 */
#include "JoystickControl.h"
#include <wx/frame.h>

//*****************************************************************************
//*****************************************************************************
/// Static constant for joystick conf. This is better than hard-coded.
static std::string joystickConfigFile("./components/JoystickCtrl/JoystickControl_conf.xml");
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
// Register event handlers
BEGIN_EVENT_TABLE(JoystickControl, wxPanel)
  // Grab custom joystick events.
  EVT_CUSTOM(wxEVT_GIMUI_JOYSTICK_MOVE, wxID_ANY, JoystickControl::OnJoystickEvent)
  EVT_CUSTOM(wxEVT_GIMUI_JOYSTICK_BUTTON_UP, wxID_ANY, JoystickControl::OnJoystickEvent)
  EVT_CUSTOM(wxEVT_GIMUI_JOYSTICK_BUTTON_DOWN, wxID_ANY, JoystickControl::OnJoystickEvent)
  
  // Get joystick-list selections.
  EVT_LISTBOX(wxID_LISTJOYSTICKNAMES, JoystickControl::OnSelectJoystick)
  
  // Get component-list selections.
  //EVT_LISTBOX(wxID_LISTCOMPONENTNAMES, JoystickControl::OnSelectComponent)
  
  // Get invert-axis selections.
  EVT_CHECKBOX(wxID_ANY, JoystickControl::OnSelectInvertAxis)
  
  // Get component option selections for different axis & buttons.
  EVT_CHOICE(wxID_ANY, JoystickControl::OnSelectFeatureComponent)
END_EVENT_TABLE()
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************

JoystickReaderThread::JoystickReaderThread(t_joystickList *joystickList,
                                           wxWindow *tWindow)
  : joysticks (joystickList),
    targetWindow (tWindow)
{
  assert(joysticks != NULL);
}
//*****************************************************************************

void* JoystickReaderThread::Entry()
{
  dPrint(1, "Starting joystickreaderthread");

  // Readerloop
  while (!TestDestroy()) {

    int joystickId = 0;
    //dPrint(1, "Looping");
    for (t_joystickListIterator joyIter = joysticks->begin();
         joyIter != joysticks->end();
         ++joyIter)
    {
      if (joyIter->first.isReadable()) { // Joystick is set to read-mode.
        
        //dPrint(1, "Joystick %d", joystickId);
        
        int axes = joyIter->first.getNumberAxes();
        
        // This checking is horribly ugly because wxWidgets has extremely stupid
        // and broken joystick-handling.
        
        // Check for changes in X- and Y-axis.
        if (axes > 1) {
          wxPoint xyAxis = joyIter->second->GetPosition();
          float xPos = convertAxisValueToFloat(xyAxis.x,
                                               joyIter->second->GetXMax(),
                                               joyIter->second->GetXMin());
          float yPos = convertAxisValueToFloat(xyAxis.y,
                                               joyIter->second->GetYMax(),
                                               joyIter->second->GetYMin());
          if (joyIter->first.compareToAxis(0, xPos) ==
              JOYSTICKCONTROL_STATUS_CHANGED)
          { // X-axis moved
            //dPrint(1, "Send x-axis move-event.");
            sendMoveEvent(joystickId, joyIter->first, 0);
          }
          if (joyIter->first.compareToAxis(1, yPos) ==
              JOYSTICKCONTROL_STATUS_CHANGED)
          { // Y-axis moved
            //dPrint(1, "Send y-axis move-event.");
            sendMoveEvent(joystickId, joyIter->first, 1);
          }
        }
        if (axes > 2) {
          int zAxis = joyIter->second->GetZPosition();
          float zPos = convertAxisValueToFloat(zAxis,
                                               joyIter->second->GetZMax(),
                                               joyIter->second->GetZMin());
          if (joyIter->first.compareToAxis(2, zPos) ==
              JOYSTICKCONTROL_STATUS_CHANGED)
          { // Z-axis moved
            //dPrint(1, "Send z-axis move-event.");
            sendMoveEvent(joystickId, joyIter->first, 2);
          }
        }
        if (axes > 3) {
          int rudder = joyIter->second->GetRudderPosition();
          float rudderPos = convertAxisValueToFloat(rudder,
                                                    joyIter->second->GetRudderMax(),
                                                    joyIter->second->GetRudderMin());
          if (joyIter->first.compareToAxis(3, rudderPos) ==
              JOYSTICKCONTROL_STATUS_CHANGED)
          { // rudder-axis moved
            //dPrint(1, "Send rudder-axis move-event.");
            sendMoveEvent(joystickId, joyIter->first, 3);
          }
        }
        if (axes > 4) {
          int uAxis = joyIter->second->GetUPosition();
          float uPos = convertAxisValueToFloat(uAxis,
                                               joyIter->second->GetUMax(),
                                               joyIter->second->GetUMin());
          if (joyIter->first.compareToAxis(4, uPos) ==
              JOYSTICKCONTROL_STATUS_CHANGED)
          { // U-axis moved
            //dPrint(1, "Send u-axis move-event.");
            sendMoveEvent(joystickId, joyIter->first, 4);
          }
        }
        if (axes > 5) {
          int vAxis = joyIter->second->GetVPosition();
          float vPos = convertAxisValueToFloat(vAxis,
                                               joyIter->second->GetVMax(),
                                               joyIter->second->GetVMin());
          if (joyIter->first.compareToAxis(5, vPos) ==
              JOYSTICKCONTROL_STATUS_CHANGED)
          { // V-axis moved
            //dPrint(1, "Send v-axis move-event.");
            sendMoveEvent(joystickId, joyIter->first, 5);
          }
        }
        
        // Check for changes in buttons.
        int newButtons = joyIter->second->GetButtonState();
        int changedButtons = joyIter->first.compareToButtons(newButtons);
        int buttonNumber = 0;
        while (changedButtons) {
          if (changedButtons & 1) { // Check if button has changed.
            //dPrint(1, "Button %d changed status.", buttonNumber);
            bool isDownEvent = false;
            if ((newButtons >> buttonNumber) & 1) { // Check if button is now down.
              isDownEvent = true;
            }
            sendButtonEvent(joystickId, joyIter->first, isDownEvent, buttonNumber);
          }
          changedButtons = changedButtons >> 1; // Shift to next button.
          ++buttonNumber;
        }
        
      }
      
      ++joystickId;
    }

    ownSleep_ms(25);
  }

  dPrint(1, "Stopping joystickreaderthread");
  
  // Free joysticklist.
  for (t_joystickListIterator joyIter = joysticks->begin();
       joyIter != joysticks->end();
       ++joyIter)
  {
    delete joyIter->second;
  }
  delete joysticks;

  return NULL;
}
//*****************************************************************************

int JoystickReaderThread::addJoystickToRead(const int joystickId)
{
  // Set joystick to read-mode.
  joysticks->at(joystickId).first.setReadModeOn();

  return JOYSTICKCONTROL_OK;
}
//*****************************************************************************

int JoystickReaderThread::removeJoystickToRead(const int joystickId)
{
  // Set joystick to not-reading mode.
  joysticks->at(joystickId).first.setReadModeOff();

  return JOYSTICKCONTROL_OK;
}
//*****************************************************************************

int JoystickReaderThread::getNumberAxesOnJoystick(const int joystickId) const
{
  return joysticks->at(joystickId).first.getNumberAxes();
}
//*****************************************************************************

int JoystickReaderThread::getNumberButtonsOnJoystick(const int joystickId) const
{
  return joysticks->at(joystickId).first.getNumberButtons();
}
//*****************************************************************************

int JoystickReaderThread::setAxisInversion(const int joystickId,
                                           const int axisId,
                                           const bool inversion)
{
  if (joysticks->at(joystickId).first.setInversion(axisId, inversion)) {
    return JOYSTICKCONTROL_OK;
  } else {
    return JOYSTICKCONTROL_ERROR;
  }
}
//*****************************************************************************

int JoystickReaderThread::sendMoveEvent(const int joystickId,
                                         const JoystickStatus &current,
                                         const int axisId)
{
  GIMUIJoystickEvent event(wxEVT_GIMUI_JOYSTICK_MOVE, current);
  event.SetEventObject(targetWindow);
  
  event.setJoystickId(joystickId);
  event.setChangeId(axisId);
  
  if (targetWindow) {
    //dPrint(1, "Sending event to window.");
    targetWindow->AddPendingEvent(event);
    return JOYSTICKCONTROL_OK;
  } else {
    return JOYSTICKCONTROL_ERROR;
  }
}
//*****************************************************************************

int JoystickReaderThread::sendButtonEvent(const int joystickId,
                                           const JoystickStatus &current,
                                           const bool buttonDownEvent,
                                           const int changedButton)
{
  wxEventType eventType;
  if (buttonDownEvent) {
    eventType = wxEVT_GIMUI_JOYSTICK_BUTTON_DOWN;
  } else {
    eventType = wxEVT_GIMUI_JOYSTICK_BUTTON_UP;
  }
  
  GIMUIJoystickEvent event(eventType, current);
  event.SetEventObject(targetWindow);
  
  event.setJoystickId(joystickId);
  event.setChangeId(changedButton);
  
  if (targetWindow) {
    dPrint(6, "Sending event about button %d.", changedButton);
    targetWindow->AddPendingEvent(event);
    return JOYSTICKCONTROL_OK;
  } else {
    return JOYSTICKCONTROL_ERROR;
  }
}
//*****************************************************************************

float JoystickReaderThread::convertAxisValueToFloat(const int axisValue,
                                                    const int maxValue,
                                                    const int minValue) const
{
  float result = 0;
  
  if (minValue < 0) { // Assume minvalue is negative equivalent of max. (Linux)
    result = (float)axisValue / (float)maxValue;
  } else if (minValue == 0) { // Minvalue 0, (Windows)
    float axisCenter = (maxValue + minValue) / 2;
    result = ((float)axisValue / axisCenter) - 1.0;
  } else {
    dPrint(1, "Unsupported joystick axis-value system, returning 0");
    result = 0;
  }
  
  return result;
}
//*****************************************************************************

PanelIdentification::PanelIdentification()
  : joystickId (0),
    type (0),
    id (0)
{}
//*****************************************************************************

PanelIdentification::PanelIdentification(const int jId,
                                         const int t,
                                         const int i)
  : joystickId (jId),
    type (t),
    id (i)
{}
//*****************************************************************************

JoystickAxisPanel::JoystickAxisPanel(wxGauge *aGauge,
                                     wxChoice *aChoice,
                                     wxCheckBox *aBox,
                                     const int aJoystickId,
                                     const int aType,
                                     const int aId)
  : axisGauge (aGauge),
    axisChoice (aChoice),
    axisCheckBox (aBox),
    ident (new PanelIdentification(aJoystickId, aType, aId))
{
  dPrint(1, "Called for joy %d type %d id %d, ident address %u", aJoystickId,
      aType, aId, ident);

  // Clientdata must be set for each possible option in each axis/button
  int count = aChoice->GetCount();
  for (int n = 0; n < count; ++n) {
    axisChoice->SetClientData(n, ident);
  }
  dPrint(1, "Set ident to %d selections.", count);
  //axisCheckBox->SetClientData(ident);
}
//*****************************************************************************

JoystickAxisPanel::~JoystickAxisPanel()
{
  dPrint(1, "Called");
  assert(ident != NULL);
  delete ident;
  ident = NULL;
}
//*****************************************************************************

JoystickButtonPanel::JoystickButtonPanel(wxStaticText *bName,
                                         wxStaticText *bStatus,
                                         wxChoice *bChoice,
                                         const int aJoystickId,
                                         const int aType,
                                         const int aId)
  : buttonName (bName),
    buttonStatus (bStatus),
    buttonChoice (bChoice),
    ident (new PanelIdentification(aJoystickId, aType, aId))
{
  dPrint(1, "Called for joy %d type %d id %d, ident address %u", aJoystickId,
      aType, aId, ident);
  
  // Clientdata must be set for each possible option in each axis/button
  int count = buttonChoice->GetCount();
  for (int n = 0; n < count; ++n) {
    buttonChoice->SetClientData(n, ident);
  }
  dPrint(1, "Set ident to %d selections.", count);
}
//*****************************************************************************

JoystickButtonPanel::~JoystickButtonPanel()
{
  dPrint(1, "Called");
  delete ident;
}
//*****************************************************************************

JoystickAxes::JoystickAxes()
  : axisPanels ()
{}
//*****************************************************************************

JoystickAxes::~JoystickAxes()
{}
//*****************************************************************************

int JoystickAxes::addAxis(wxGauge *aGauge,
                          wxChoice *aChoice,
                          wxCheckBox *aBox,
                          const int joystickId,
                          const int aId)
{
  axisPanels.push_back(new JoystickAxisPanel(aGauge, aChoice, aBox, joystickId,
                       JOYSTICKCONTROL_PANEL_AXIS, aId));
  return axisPanels.size();
}
//*****************************************************************************

int JoystickAxes::setAxisPosition(const int axisId,
                                  const float axisValue)
{
  int gaugeval = int((axisValue + 1.0) * 50);
  (axisPanels[axisId])->axisGauge->SetValue(gaugeval);
  return 1;
}
//*****************************************************************************

int JoystickAxes::setToChoice(const int axisId,
                              const int selectionId,
                              const bool invert)
{
  dPrint(1, "Setting axischoice to %d for button %d", selectionId, axisId);
  if (axisId < axisPanels.size()) {
    (axisPanels[axisId])->axisChoice->SetSelection(selectionId);
    (axisPanels[axisId])->axisCheckBox->SetValue(invert);
    return JOYSTICKCONTROL_OK;
  } else {
    return JOYSTICKCONTROL_ERROR;
  }
}
//*****************************************************************************

JoystickButtons::JoystickButtons()
  : buttonPanels ()
{}
//*****************************************************************************

JoystickButtons::~JoystickButtons()
{}
//*****************************************************************************

int JoystickButtons::addButton(wxStaticText *bName,
                               wxStaticText *bStatus,
                               wxChoice *bChoice,
                               const int joystickId,
                               const int bId)
{
  buttonPanels.push_back(new JoystickButtonPanel(bName, bStatus, bChoice,
                        joystickId, JOYSTICKCONTROL_PANEL_BUTTON, bId));
  return buttonPanels.size();
}
//*****************************************************************************
    
int JoystickButtons::setButtonPosition(const int buttonId,
                                       const bool position)
{
  wxString statusText;
  if (position) {
    statusText.Printf("Down");
  } else {
    statusText.Printf("Up");
  }
  (buttonPanels[buttonId])->buttonStatus->SetLabel(statusText);
  return 1;
}
//*****************************************************************************

int JoystickButtons::setToChoice(const int buttonId,
                                 const int selectionId)
{
  dPrint(1, "Setting buttonchoice to %d for button %d", selectionId, buttonId);
  if (buttonId < buttonPanels.size()) {
    (buttonPanels[buttonId])->buttonChoice->SetSelection(selectionId);
    return JOYSTICKCONTROL_OK;
  } else {
    return JOYSTICKCONTROL_ERROR;
  }
}
//*****************************************************************************

AxisIdentifications::AxisIdentifications()
  : idents (),
    freeId (JOYSTICKCONTROL_AXISIDENTSTART)
{}
//*****************************************************************************

AxisIdentifications::~AxisIdentifications()
{}
//*****************************************************************************
    
int AxisIdentifications::addIdent(const int wxId,
                                  const int joystickId,
                                  const int axisId)
{
  PanelIdentification newIdent(joystickId, JOYSTICKCONTROL_PANEL_AXIS, axisId);
  if ((idents.insert(t_identMapPair(wxId, newIdent))).second) {
    if (wxId >= freeId)
      freeId = wxId+1;
    return JOYSTICKCONTROL_OK;
  } else {
    return JOYSTICKCONTROL_ERROR;
  }
}
//*****************************************************************************

int AxisIdentifications::addNewAxis(const int joystickId,
                                    const int axisId)
{
  PanelIdentification newIdent(joystickId, JOYSTICKCONTROL_PANEL_AXIS, axisId);
  if ((idents.insert(t_identMapPair(freeId, newIdent))).second) {
    int retval = freeId;
    ++freeId;
    return retval;
  } else {
    return JOYSTICKCONTROL_ERROR;
  }
}
//*****************************************************************************

int AxisIdentifications::findIdent(const int wxId,
                                   PanelIdentification &foundIdent)
{
  t_identMapConstIterator identIter = idents.find(wxId);
  if (identIter == idents.end()) { // Not found.
    return JOYSTICKCONTROL_ERROR;
  } else { // Found.
    foundIdent = identIter->second;
    return JOYSTICKCONTROL_OK;
  }
}
//*****************************************************************************

JoystickInformationPanel::JoystickInformationPanel(wxPanel *mWindow,
                                                   wxSizer *pSizer,
                                                   const int jId)
  : mainWindow (mWindow),
    currentPanel (NULL),
    parentSizer (pSizer),
    joystickId (jId),
    joystickAxes (),
    joystickButtons (),
    choiceIdent (jId, JOYSTICKCONTROL_PANEL_CONFIG, 0)
{
  //DEBUG Check validity
  assert(mWindow != NULL);
  assert(parentSizer != NULL);
}
//*****************************************************************************

JoystickInformationPanel::~JoystickInformationPanel()
{
  // Remove current sizer if any
  if (currentPanel != NULL) {
    dPrint(1, "Removing panel.");
    parentSizer->Detach(currentPanel);
    currentPanel->Destroy();
    currentPanel = NULL;
  } else {
    dPrint(1, "No panel.");
  }
}
//*****************************************************************************

int JoystickInformationPanel::initialize(const int nAxes,
                                         const int nButtons,
                                         const wxArrayString &axisSelections,
                                         const wxArrayString &buttonSelections,
                                         AxisIdentifications &axisReferences,
                                         const wxArrayString &configurations)
{
  // Create a new panel
  wxPanel* joystickInformationPanel = new wxPanel(mainWindow, wxID_ANY,
                                                  wxDefaultPosition,
                                                  wxDefaultSize,
                                                  wxTAB_TRAVERSAL);

  // And a sizer for it
  wxBoxSizer* joystickInformationSizer = new wxBoxSizer(wxVERTICAL);
  
  //TODO Add configuration here.
  wxBoxSizer* configSizer = new wxBoxSizer(wxHORIZONTAL);
  wxStaticText* configText = new wxStaticText(joystickInformationPanel,
      wxID_ANY, wxT("Configuration:"), wxDefaultPosition, wxDefaultSize, 0);
  wxChoice* configChoice = new wxChoice(joystickInformationPanel, wxID_ANY,
      wxDefaultPosition, wxDefaultSize, configurations, 0);
  configSizer->Add(configText, 0, wxALL, 5);
  configSizer->Add(configChoice, 0, wxALL, 5);
  
  // Set ident so the event contains info which joystick we are adjusting.
  int count = configurations.GetCount();
  for (int n = 0; n < count; ++n) {
    dPrint(2, "Setting ident for choice %d", n);
    configChoice->SetClientData(n, &choiceIdent);
  }
  
  joystickInformationSizer->Add(configSizer);

  // Draw axes
  for (int n = 0; n < nAxes; ++n) {
    wxBoxSizer* axisSizer = new wxBoxSizer(/* wxEXPAND | */wxHORIZONTAL);
    
    wxGauge* axisGauge = new wxGauge(joystickInformationPanel, wxID_ANY, 100,
        wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL);
    wxChoice* axisChoice = new wxChoice(joystickInformationPanel, wxID_ANY,
        wxDefaultPosition, wxDefaultSize, axisSelections, 0);
        
    int checkBoxId = axisReferences.addNewAxis(this->joystickId, n);
    if (checkBoxId < 0) {
      dPrint(1, "!!!Internal error!!!");
    }
    wxCheckBox* axisCheckBox = new wxCheckBox(joystickInformationPanel,
        checkBoxId, "", wxDefaultPosition, wxDefaultSize, 0);
    
    // Set ranges.
    axisGauge->SetRange(100);

    joystickAxes.addAxis(axisGauge, axisChoice, axisCheckBox, this->joystickId, n);

    axisSizer->Add(axisGauge, 0, wxALL, 5);
    axisSizer->Add(axisChoice, 0, wxALL, 5);
    axisSizer->Add(axisCheckBox, 0, wxALL, 5);

    joystickInformationSizer->Add(axisSizer);
  }

  // Draw buttons
  for (int n = 0; n < nButtons; ++n) {
    wxString buttonText;
    buttonText.Printf(_T("Button %d"), n+1);
    
    wxBoxSizer* buttonSizer = new wxBoxSizer(/*wxEXPAND | */wxHORIZONTAL);

    wxStaticText* buttonName = new wxStaticText(joystickInformationPanel,
        wxID_ANY, buttonText, wxDefaultPosition, wxDefaultSize, 0);

    wxStaticText* buttonStatus = new wxStaticText(joystickInformationPanel,
        wxID_ANY, wxT("Up"), wxDefaultPosition, wxDefaultSize, 0);
        
    wxChoice* buttonChoice = new wxChoice(joystickInformationPanel, wxID_ANY,
        wxDefaultPosition, wxDefaultSize, buttonSelections, 0);

    joystickButtons.addButton(buttonName, buttonStatus, buttonChoice,
                              this->joystickId, n);

    buttonSizer->Add(buttonName, 0, wxALL, 5);
    buttonSizer->Add(buttonStatus, 0, wxALL, 5);
    buttonSizer->Add(buttonChoice, 0, wxALL, 5);

    joystickInformationSizer->Add(buttonSizer);
  }

  joystickInformationPanel->SetSizer(joystickInformationSizer);
  joystickInformationPanel->Layout();
  joystickInformationSizer->Fit(joystickInformationPanel);

  currentPanel = joystickInformationPanel;

  parentSizer->Add(joystickInformationPanel, 1, wxEXPAND | wxALL, 5);
  parentSizer->Layout();
  
  //TODO Update axes & buttons to current situation.
  

  return nAxes+nButtons;
}
//*****************************************************************************

int JoystickInformationPanel::setAxisToChoice(const int axisId,
                                              const int selectionId,
                                              const bool invert)
{
  return joystickAxes.setToChoice(axisId, selectionId, invert);
}
//*****************************************************************************
    
int JoystickInformationPanel::setButtonToChoice(const int buttonId,
                                                const int selectionId)
{
  return joystickButtons.setToChoice(buttonId, selectionId);
}
//*****************************************************************************

JoystickComponentContainer::JoystickComponentContainer()
  : components ()/*,
    axisEventReaders (),
    buttonEventReaders ()*/
{}
//*****************************************************************************

JoystickComponentContainer::~JoystickComponentContainer()
{
  for (t_componentListIterator cIter = components.begin();
       cIter != components.end();
       ++cIter)
  {
    delete *cIter;
    *cIter = NULL;
  }
}
//*****************************************************************************
    
int JoystickComponentContainer::forwardEvent(const GIMUIJoystickEvent &event)
{ 
  int n = 0;

  for (t_componentListIterator compIter = components.begin();
       compIter != components.end();
       ++compIter)
  {
    //dPrint(6, "Component %d sent event %d.", *compIter, event.GetEventType());
    (*compIter)->eventReceiver(event);
    ++n;
  }
  
  return n;
}
//*****************************************************************************

int JoystickComponentContainer::refreshOptionLists()
{
  // Clear old options-lists just in case.
  axisOptions.clear();
  buttonOptions.clear();
  
  int compId = 0;
  
  // Add empty options
  axisOptions.push_back(OptionInformation(-1, -1, ""));
  buttonOptions.push_back(OptionInformation(-1, -1, ""));
  
  // Generate lists from each component.
  for (t_componentListIterator compIter = components.begin();
       compIter != components.end();
       ++compIter)
  {
    JoystickControlComponent *compPtr = *compIter;
    if (compPtr->activationStatus.isActive()) {
      dPrint(1, "Component %d active, getting axis- and button-options.", compId);
      // Get optionlists from current component if it is active
      t_optionList curAxisOptions;
      t_optionList curButtonOptions;
      int n = 0;
      n = compPtr->listAxisOptions(curAxisOptions);
      dPrint(1, "Got %d axis-options.", n);
      n = compPtr->listButtonOptions(curButtonOptions);
      dPrint(1, "Got %d button-options.", n);
      
      // Add to local (this class instance) lists.
      for (t_optionListConstIterator aOptIter = curAxisOptions.begin();
           aOptIter != curAxisOptions.end();
           ++aOptIter)
      {
        axisOptions.push_back(OptionInformation(compId, aOptIter->first,
            aOptIter->second));
      }
      
      for (t_optionListConstIterator bOptIter = curButtonOptions.begin();
           bOptIter != curButtonOptions.end();
           ++bOptIter)
      {
        buttonOptions.push_back(OptionInformation(compId, bOptIter->first,
            bOptIter->second));
      }
    } else {
      dPrint(1, "Component %d was not active.", compId);
    }
    ++compId;
  }

  return JOYSTICKCONTROL_OK;
}
//*****************************************************************************

int JoystickComponentContainer::addComponent(JoystickControlComponent* comp)
{
  if (comp != NULL) {
    components.push_back(comp);
    return JOYSTICKCONTROL_OK;
  }
  return JOYSTICKCONTROL_ERROR;
}
//*****************************************************************************

int JoystickComponentContainer::activateAllComponents()
{
  int n = 0;

  for (t_componentListIterator compIter = components.begin();
       compIter != components.end();
       ++compIter)
  {
    if ((*compIter)->startComponent()) {
      ++n;
    }
  }
  
  return n;
}
//*****************************************************************************

int JoystickComponentContainer::activateComponents(gimi::GIMIService &target)
{
  int n = 0;

  for (t_componentListIterator compIter = components.begin();
       compIter != components.end();
       ++compIter)
  {
    JoystickControlComponent* comp = *compIter;
    dPrint(ODTEST,"Testing service %p against target", comp);

    // Check that target matches to output/input type of component
    if (target.serviceType == GIMI_SERVICETYPE_PROVIDED ||
        target.serviceType == GIMI_SERVICETYPE_ACCEPTED) {
      dPrint(1, "ServiceType is provided or accepted.");
      
      if (target.majorServiceId > 0 &&
          (target.majorServiceId == comp->getComponentInputType() ||
           target.majorServiceId == comp->getComponentOutputType())) {
        // Set target to component
        dPrint(1, "Target '%s' major '%u' matches to either component type: I:%d or O:%d",
               target.clientName.c_str(),
               target.majorServiceId, 
               comp->getComponentInputType(),
               comp->getComponentOutputType());
        
        // Add target.
        comp->addTarget(target);

        // Start component
        if (comp->startComponent()) {
          dPrint(ODTEST, "Succesfully started component '%s' to target '%s'",
                 comp->getComponentName().c_str(),
                 target.clientName.c_str());
          ++n;

        } else {
          dPrint(ODTEST, "Failed to start component");

        }
      } else {
        dPrint(ODTEST, "Given target '%s' Major %d didn't match the component",
               target.clientName.c_str(),
               target.majorServiceId);
        
      }
    } else {
      dPrint(1, "Target '%s' had invalid serviceType '%d'", 
             target.clientName.c_str(),
             target.serviceType);

    }
  }
  
  return n;
}
//*****************************************************************************

int JoystickComponentContainer::listComponents(std::vector<std::string> &componentNames,
                                               bool onlyActive /* = false */)
{
  int n = 0;
  for (t_componentListIterator compIter = components.begin();
       compIter != components.end();
       ++compIter)
  {
    JoystickControlComponent* comp = *compIter;
    if (onlyActive) {
      if (comp->activationStatus.isActive()) {
        componentNames.push_back(comp->getComponentName());
        ++n;
      }
    } else {
      componentNames.push_back(comp->getComponentName());
      ++n;
    }
  }
  return n;
}
//*****************************************************************************

int JoystickComponentContainer::listAxisOptions(wxArrayString &allAxisOptions) const
{
  int n = 0;
  wxString optionString;
  for (t_selectOptionListConstIterator aIter = axisOptions.begin();
       aIter != axisOptions.end();
       ++aIter)
  {
    if (aIter->componentId < 0) { // Empty selection
      optionString.Clear();
    } else { // Normal selections
      std::string componentName = (components[aIter->componentId])->getComponentName();
      optionString.Printf(wxT("%s - %s"), componentName.c_str(),
          (aIter->optionDescription).c_str());
    }
    allAxisOptions.Add(optionString);
    ++n;
  }
  
  return n;
}
//*****************************************************************************

int JoystickComponentContainer::listAxisOptions(
    std::vector< std::pair <std::string, std::string> > &axisOptionsList,
    bool onlyActive /* = false */) const
{
  int n = 0;
  for (t_componentListConstIterator compIter = components.begin();
       compIter != components.end();
       ++compIter)
  {
    bool shouldAdd = true;
    if (onlyActive && !(*compIter)->activationStatus.isActive()) {
      shouldAdd = false;
    }
    if (shouldAdd) {
      std::string componentName = (*compIter)->getComponentName();
      t_optionList axisOptsList;
      (*compIter)->listAxisOptions(axisOptsList);
      for (t_optionListConstIterator optIter = axisOptsList.begin();
           optIter != axisOptsList.end();
           ++optIter)
      {
        dPrint(4, "Found %s - %s", componentName.c_str(), optIter->second.c_str());
        axisOptionsList.push_back(t_stringPair(componentName, optIter->second));
        ++n;
      }
    } else {
      dPrint(4, "Component %s was not active", (*compIter)->getComponentName().c_str());
    }
  }
  return n;
}
//*****************************************************************************

int JoystickComponentContainer::listButtonOptions(wxArrayString &allButtonOptions) const
{
  int n = 0;
  wxString optionString;
  for (t_selectOptionListConstIterator bIter = buttonOptions.begin();
       bIter != buttonOptions.end();
       ++bIter)
  {
    if (bIter->componentId < 0) { // Empty selection
      optionString.Clear();
    } else { // Normal selections
      std::string componentName = (components[bIter->componentId])->getComponentName();
      optionString.Printf(wxT("%s - %s"), componentName.c_str(),
          (bIter->optionDescription).c_str());
    }
    allButtonOptions.Add(optionString);
    ++n;
  }
  
  return n;
}
//*****************************************************************************

int JoystickComponentContainer::listButtonOptions(
    std::vector< std::pair <std::string, std::string> > &buttonOptionsList,
    bool onlyActive /* = false */) const
{
  int n = 0;

  for (t_componentListConstIterator compIter = components.begin();
       compIter != components.end();
       ++compIter)
  {
    bool shouldAdd = true;
    if (onlyActive && !(*compIter)->activationStatus.isActive()) {
      shouldAdd = false;
    }
    if (shouldAdd) {
      std::string componentName = (*compIter)->getComponentName();
      t_optionList buttonOptsList;
      (*compIter)->listButtonOptions(buttonOptsList);
      for (t_optionListConstIterator optIter = buttonOptsList.begin();
           optIter != buttonOptsList.end();
           ++optIter)
      {
        dPrint(4, "Found %s - %s", componentName.c_str(), optIter->second.c_str());
        buttonOptionsList.push_back(t_stringPair(componentName, optIter->second));
        ++n;
      }
    } else {
      dPrint(4, "Component %s was not active", (*compIter)->getComponentName().c_str());
    }
  }

  return n;
}
//*****************************************************************************

int JoystickComponentContainer::findAxisIdFor(const std::string componentName,
                                              const std::string axisName)
{
  dPrint(6 ,"Called for component %s, axis %s", componentName.c_str(), axisName.c_str());
  int axisSelectionId = -1;
  int n = 0;
  bool loop = true;
  
  // Find component.
  for (t_componentListConstIterator compIter = components.begin();
       compIter != components.end();
       ++compIter)
  {
    if (!loop) {
      break;
    }
    
    std::string compName = (*compIter)->getComponentName();
    if (compName == componentName) {
      dPrint(6, "Matched %s, with componentId %d", compName.c_str(), n);
      // Go trough buttons and compare names to find id.
      for(t_selectOptionListConstIterator optIter = axisOptions.begin();
          optIter != axisOptions.end();
          ++optIter)
      {
        if (optIter->componentId == n &&
            optIter->optionDescription == axisName)
        {
          dPrint(2, "Found id %d for axisoption %s in component %s",
              optIter->optionId + 1, axisName.c_str(), componentName.c_str());
          axisSelectionId = optIter->optionId + 1;
          loop = false;
          break;
        }
      }
    }
    ++n;
  }
  
  return axisSelectionId;
}
//*****************************************************************************

int JoystickComponentContainer::findButtonIdFor(const std::string componentName,
                                                const std::string buttonName)
{
  int buttonSelectionId = -1;
  int n = 0;
  bool loop = true;
  
  // Find component.
  for (t_componentListConstIterator compIter = components.begin();
       compIter != components.end();
       ++compIter)
  {
    if (!loop) {
      break;
    }
    
    std::string compName = (*compIter)->getComponentName();
    if (compName == componentName) {
      // Go trough buttons and compare names to find id.
      for(t_selectOptionListConstIterator optIter = buttonOptions.begin();
          optIter != buttonOptions.end();
          ++optIter)
      {
        if (optIter->componentId == n &&
            optIter->optionDescription == buttonName)
        {
          dPrint(2, "Found id %d for buttonoption %s in component %s",
              optIter->optionId + 1, buttonName.c_str(), componentName.c_str());
          buttonSelectionId = optIter->optionId + 1;
          loop = false;
          break;
        }
      }
    }
    ++n;
  }
  
  return buttonSelectionId;
}
//*****************************************************************************

int JoystickComponentContainer::setAxisOption(const int selectionId,
                                              const int joystickId,
                                              const int axisId)
{
  dPrint(6, "Called with selectionId %d, joystickId %d, axisId %d", selectionId,
         joystickId, axisId);
  if (selectionId < axisOptions.size()) {
    int componentId = axisOptions[selectionId].componentId;
    int optionId = axisOptions[selectionId].optionId;
    if (componentId < 0) { // Empty selection
      dPrint(6, "ComponentId %d. Empty selection, clearing in all components.", componentId);
      // Go through all components.
      for (t_componentListIterator compIter = components.begin();
         compIter != components.end();
         ++compIter)
      {
        (*compIter)->setAxisOption(-1, joystickId, axisId);
      }
      return JOYSTICKCONTROL_OK;
    } else { // Normal selection
      dPrint(6, "Normal selection for component %d", componentId);
      return (components[componentId])->setAxisOption(optionId, joystickId, axisId);
    }
  } else {
    return JOYSTICKCONTROL_ERROR;
  }
}
//*****************************************************************************
    
int JoystickComponentContainer::setButtonOption(const int selectionId,
                                                const int joystickId,
                                                const int buttonId)
{
  if (selectionId < buttonOptions.size()) { 
    int componentId = buttonOptions[selectionId].componentId;
    int optionId = buttonOptions[selectionId].optionId;
    if (componentId < 0) { // Empty selection
      // Go through all components.
      for (t_componentListIterator compIter = components.begin();
         compIter != components.end();
         ++compIter)
      {
        (*compIter)->setButtonOption(-1, joystickId, buttonId);
      }
      return JOYSTICKCONTROL_OK;
    } else {
      return (components[componentId])->setButtonOption(optionId, joystickId, buttonId);
    }
  } else {
    return JOYSTICKCONTROL_ERROR;
  }
}
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************

OptionInformation::OptionInformation(const int aComponentId,
                                     const int aOptionId,
                                     const std::string aOptionDescription)
  : componentId (aComponentId),
    optionId (aOptionId),
    optionDescription (aOptionDescription)
{}

//*****************************************************************************

bool JoystickControl::SetTargetServices(const std::vector<gimi::GIMIService> &aGIMIServiceArray)
{
  bool result = false;
  // Activate components that match target(s)
  iTargetServices = aGIMIServiceArray;


  if (aGIMIServiceArray.empty()) {
    dPrint(ODWARN,"Warning: Setting empty TargetService list for JoystickControl");

  } else {
    assert(iTargetServices.size() > 0);
    dPrint(ODTEST,"Running activateComponents");
    //    const int n = components.activateComponents(iTargetServices[0]);
    int n = 0;
    for(EACH_IN_i(iTargetServices)) {
      n += components.activateComponents(*i);
    }
    dPrint(1, "Activated %d components.", n);
    result = (n > 0);
    
  }

  // Get options from all activated components and list them.
  components.refreshOptionLists();
  dPrint(1, "Option lists refreshed.");

  // Get number of joysticks.
  int numberOfJoysticks = wxJoystick::GetNumberJoysticks();
  
  /*
  wxString nojStr;
  nojStr.Printf(_T("Found %d joysticks"), numberOfJoysticks);
  mainPanel.Label_Name1->SetLabel(nojStr);
  */

  wxArrayString joystickNames;
  t_joystickList *joystickList = new t_joystickList;

  // Create joystick objects.
  for (int n = wxJOYSTICK1; n < numberOfJoysticks; ++n) {
    wxJoystick *newJoy;

    newJoy = new wxJoystick(n);
    if (newJoy->IsOk()) { // Add only valid joysticks to the list
      wxString joyName = newJoy->GetProductName();
      joystickNames.Add(joyName);
      joystickList->push_back(t_joystickReference(JoystickStatus(
          newJoy->GetNumberAxes(), newJoy->GetNumberButtons()), newJoy));
      dPrint(1, "Added joystick %d (%s)", n, joyName.c_str());
      dPrint(1, "X minmax: %d/%d, Y minmax: %d/%d", newJoy->GetXMin(),
          newJoy->GetXMax(), newJoy->GetYMin(), newJoy->GetYMax());
    } else {
      delete newJoy;
    }
  }

  mainPanel.Listbox_JoystickNames->Set(joystickNames);

  this->Layout();

  //// Settings initialization.
  //TODO Make more automatic.
  //TODO Read stuff from settings in settingsHandler constructor.
  //TODO Make calls that set a joystick to certain configuration.
  dPrint(1, "** Setting settings.");
  gim::CSettings *settings = new gim::CSettings;
  settings->ReadSettingsXMLFile(joystickConfigFile);
  
  std::vector< t_stringPair > axisOptions;
  std::vector< t_stringPair > buttonOptions;
  
  dPrint(1, "** List axes in activated components");
  components.listAxisOptions(axisOptions, true);
  dPrint(1, "** List buttons in activated components.");
  components.listButtonOptions(buttonOptions, true);
  dPrint(1, "** Initialize settings");
  
  if (settingsHandler) delete settingsHandler;
  settingsHandler = new JoystickControlSettingsHandler(settings, axisOptions,
                                                       buttonOptions);
  dPrint(1, "** End settings-init.");
  
  // Start joystickThread - create instance.
  dPrint(1, "Creating joystickthread instance.");
  if (joystickReaderThread) delete joystickReaderThread;
  joystickReaderThread = new JoystickReaderThread(joystickList, this);
  joystickReaderThread->Create();
  joystickReaderThread->Run();

  this->Layout();
  
  return result;
}
//*****************************************************************************

JoystickControl::JoystickControl(gimi::GIMI *aGIMIPtr, wxWindow *ParentWindow)
  : wxPanel(ParentWindow),
    iParentFrame(NULL),
    iGIMIPtr(aGIMIPtr),
    iTargetServices(),
    joystickReaderThread (NULL),
    mainPanel (this,wxID_ANY),
    joystickPanels (),
    components (),
    axisIdents (),
    settingsHandler (NULL)
{
  // Get component sizer
  wxSizer *cSizer = mainPanel.panel_JoystickSelection->GetSizer();
  assert(cSizer != NULL);
  wxBoxSizer *componentSizer = new wxBoxSizer(wxVERTICAL);
  cSizer->Add(componentSizer, 1, wxEXPAND, 5);
  
  // Add components here! //
  components.addComponent(new JCMaCIJointGroupControl(iGIMIPtr, componentSizer,
                                                      mainPanel.panel_JoystickSelection));
  components.addComponent(new JCMaCISpeedCtrl(iGIMIPtr, componentSizer,
					      mainPanel.panel_JoystickSelection));
  // End add components ////
  
  // Create a sizer and add the main panel to it.
  wxGridSizer *sizer=new wxGridSizer(1,1);
  
  sizer->Add(&mainPanel,1,wxEXPAND|wxALL,1);
  this->SetSizer(sizer);
  sizer->SetSizeHints(this);

  // Set title for our frame
  if (iParentFrame!=NULL)
  {
    iParentFrame->Fit();
    iParentFrame->Show(true);
    wxString title;
    title.Printf(_T("JoystickControl Window"));
    iParentFrame->SetTitle(title);
  }
}
//*****************************************************************************

JoystickControl::~JoystickControl()
{
  joystickReaderThread->Delete();
  //  joystickReaderThread->Wait();

  dPrint(1, "Deleted joystickreaderthread");
  //TODO FIXME Wait?!?!?
  ownSleep_ms(2000);
}
//*****************************************************************************

void JoystickControl::OnReceive(int r, gimi::GIMIMessage *message)
{
  return;
}
//*****************************************************************************

void JoystickControl::OnConnect()
{
  return;
}
//*****************************************************************************

void JoystickControl::OnDisconnect()
{
  //TODO Draw warning?
  return;
}
//*****************************************************************************

void JoystickControl::OnSelectJoystick(wxCommandEvent &event)
{
  int numberOfSelections;
  wxArrayInt joystickSelections;
  wxArrayString axisSelections;
  wxArrayString buttonSelections;
  wxArrayString configList;
  
  // Get lists of possible selection options for axes/buttons.
  components.listAxisOptions(axisSelections);
  components.listButtonOptions(buttonSelections);
  
  // Get configurations.
  settingsHandler->listConfigurations(configList);

  // Get selectionlist from window.
  numberOfSelections =
      mainPanel.Listbox_JoystickNames->GetSelections(joystickSelections);

  // Compare selections and current joystick panels.
  // Not very efficient but that doesn't matter since number of joysticks
  // won't be extremely high in any situation.

  // First remove non-selected joysticks.
  t_joystickPanelsIterator jpIter = joystickPanels.begin();
  while (jpIter != joystickPanels.end()) {
    if (joystickSelections.Index(jpIter->first) == wxNOT_FOUND) {
      // Joystick no longer selected, remove it's panel.
      dPrint(3, "Joystick %d no longer selected, removing.", jpIter->first);
      
      // Remove joystick readmode.
      joystickReaderThread->removeJoystickToRead(jpIter->first);
      
      t_joystickPanelsIterator removeIter = jpIter;
      ++jpIter;
      joystickPanels.erase(removeIter);
    } else {
      ++jpIter;
    }
  }

  // Add panels if they don't exist.
  for (int n = 0; n < numberOfSelections; ++n) {
    int joystickNumber = joystickSelections.Item(n);

    // Check if panel exists.
    t_joystickPanelsIterator panelIter =
        joystickPanels.find(joystickNumber);
    if (panelIter == joystickPanels.end()) { // Does not exist, add it.
      dPrint(3, "Panel for joystick %d does not exist. Creating.",
             joystickNumber);
      panelIter = (joystickPanels.insert(t_joystickPanelsPair(joystickNumber,
                   JoystickInformationPanel(&mainPanel, mainPanel.GetSizer(),
                   joystickNumber)))).first;
      // Initialize panel.
      int axes = joystickReaderThread->getNumberAxesOnJoystick(joystickNumber);
      int buttons = joystickReaderThread->getNumberButtonsOnJoystick(joystickNumber);
      
      panelIter->second.initialize(axes, buttons, axisSelections,
          buttonSelections, axisIdents, configList);
      
      // Set joystick to readmode.
      joystickReaderThread->addJoystickToRead(joystickNumber);
      
    } else {
      dPrint(3, "Panel for joystick %d already exists.", joystickNumber);
    }
  }

  // Update layout
  mainPanel.Layout();
}
//*****************************************************************************

void JoystickControl::OnSelectFeatureComponent(wxCommandEvent &event)
{
  dPrint(3, "Got selection event %d.", event.GetSelection());
  void *temp = NULL;
  PanelIdentification *ident = NULL;
  temp = event.GetClientData();
  //temp = event.GetClientObject();
  dPrint(3, "Got address %u for clientdata.", temp);
  ident = reinterpret_cast<PanelIdentification *>(temp);
 
  if (temp == NULL) {
    dPrint(1, "Got null from GetClientData()");
  } else {
    if (ident == NULL) {
      dPrint(1, "Got null from reinterpret.");
    } else {
      if (ident->type == JOYSTICKCONTROL_PANEL_AXIS) {
        dPrint(6, "PanelAxis called.");
        if (components.setAxisOption(event.GetSelection(), ident->joystickId,
                                     ident->id) == JOYSTICKCONTROL_OK)
        {
          dPrint(3, "Set selectionId %d to read axis %d in joystick %d",
                 event.GetSelection(), ident->id, ident->joystickId);
        } else {
          dPrint(1, "Failed to set selectionId to read axis %d in "
              "joystick %d", event.GetSelection(), ident->id, ident->joystickId);
        }
      } else if (ident->type == JOYSTICKCONTROL_PANEL_BUTTON) {
        dPrint(1, "PanelButton called.");
        if (components.setButtonOption(event.GetSelection(), ident->joystickId,
                                       ident->id) == JOYSTICKCONTROL_OK)
        {
          dPrint(3, "Set selectionId %d to read button %d in joystick %d",
                 event.GetSelection(), ident->id, ident->joystickId);
        } else {
          dPrint(1, "Failed to set selectionId to read button %d in "
              "joystick %d", event.GetSelection(), ident->id, ident->joystickId);
        }
      } else if (ident->type == JOYSTICKCONTROL_PANEL_CONFIG) {
        // When choicebox with configurations is clicked.
        int configId = event.GetSelection();
        dPrint(3, "Configuration selection event %d joystick %d",
            event.GetSelection(), ident->joystickId);
        
        t_axisConfigVector newAxisConfiguration;
        t_buttonConfigVector newButtonConfiguration;
        int nAxes = settingsHandler->listAxesForConfiguration(newAxisConfiguration,
                                                              configId);
        
        int nButtons = settingsHandler->listButtonsForConfiguration(newButtonConfiguration,
                                                                    configId);
        
        dPrint(3, "Found %d axes and %d buttons for joystick %d from configuration %d",
               nAxes, nButtons, ident->joystickId, configId+1);
        
        for (t_axisConfigVectorConstIterator newAIter = newAxisConfiguration.begin();
             newAIter != newAxisConfiguration.end();
             ++newAIter)
        {
          dPrint(6, "Finding in %s axis %s.",
              newAIter->componentName.c_str(), newAIter->functionName.c_str());
          int axisSelectionId = components.findAxisIdFor(newAIter->componentName,
                                                         newAIter->functionName);
          dPrint(6, "Got %d for axisSelectionId", axisSelectionId);
          
          // Find panel
          if (axisSelectionId > -1) {
            // Actually set the axis
            if (components.setAxisOption(axisSelectionId, ident->joystickId,
                                         newAIter->axisId) == JOYSTICKCONTROL_OK)
            {
              dPrint(3, "Set selectionId %d to read axis %d in joystick %d",
                     axisSelectionId, newAIter->axisId, ident->joystickId);
            } else {
              dPrint(1, "Failed to set selectionId to read axis %d in "
                  "joystick %d", axisSelectionId, newAIter->axisId, ident->joystickId);
            }
            
            // Set inversion
            if (newAIter->invert) {
              if (joystickReaderThread->setAxisInversion(ident->joystickId,
                  newAIter->axisId, newAIter->invert) != JOYSTICKCONTROL_OK)
              {
                dPrint(1, "Could not invert axis %d on joystick %d",
                    newAIter->axisId, ident->joystickId);
              } else {
                dPrint(3, "Inverted axis %d on joystick %d",
                    newAIter->axisId, ident->joystickId);
              }
            }
            
            dPrint(1, "Find panel and set the axis visually");
            
            t_joystickPanelsIterator jpIter = joystickPanels.find(ident->joystickId);
            if (jpIter != joystickPanels.end()) {
              if (jpIter->second.setAxisToChoice(newAIter->axisId,
                    axisSelectionId, newAIter->invert) == JOYSTICKCONTROL_OK)
              {
                dPrint(3, "Successfully set joystick %d, axis %d to selection %d",
                       ident->joystickId, newAIter->axisId, axisSelectionId);
              } else {
                dPrint(1, "Failed to set joystick %d, axis %d to selection %d",
                       ident->joystickId, newAIter->axisId, axisSelectionId);
              }
            }
          }
        }
        
        for (t_buttonConfigVectorConstIterator newBIter = newButtonConfiguration.begin();
             newBIter != newButtonConfiguration.end();
             ++newBIter)
        {
          dPrint(6, "Finding in %s button %s.",
              newBIter->componentName.c_str(), newBIter->functionName.c_str());
          
          int buttonSelectionId = components.findButtonIdFor(newBIter->componentName,
                                                             newBIter->functionName);
          dPrint(6, "Got %d for buttonSelectionId", buttonSelectionId);
          //TODO Check for buttonSelectionId validity?
          // Find panel
          if (buttonSelectionId > -1) {
            //TODO Actually set the button
            if (components.setButtonOption(buttonSelectionId, ident->joystickId,
                                           newBIter->buttonId) == JOYSTICKCONTROL_OK)
            {
              dPrint(3, "Set selectionId %d to read axis %d in joystick %d",
                     buttonSelectionId, newBIter->buttonId, ident->joystickId);
            } else {
              dPrint(1, "Failed to set selectionId to read axis %d in "
                  "joystick %d", buttonSelectionId, newBIter->buttonId, ident->joystickId);
            }
            
            t_joystickPanelsIterator jpIter = joystickPanels.find(ident->joystickId);
            if (jpIter != joystickPanels.end()) {
              if (jpIter->second.setButtonToChoice(newBIter->buttonId,
                  buttonSelectionId) == JOYSTICKCONTROL_OK)
              {
                dPrint(3, "Successfully set joystick %d, axis %d to selection %d",
                       ident->joystickId, newBIter->buttonId, buttonSelectionId);
              } else {
                dPrint(1, "Failed to set joystick %d, axis %d to selection %d",
                       ident->joystickId, newBIter->buttonId, buttonSelectionId);
              }
            }
          }
        }
        
        dPrint(3, "End autoconfig");
      }
    }
  }
}
//*****************************************************************************

void JoystickControl::OnSelectInvertAxis(wxCommandEvent &event)
{
  dPrint(3, "InvertAxis selected.");
  PanelIdentification ident;
  int wxId = event.GetId();
  
  int retval = axisIdents.findIdent(wxId, ident);
 
  if (retval != JOYSTICKCONTROL_OK) {
    dPrint(1, "Failed to find axis for wxId %d", wxId);
  } else {
    if (ident.type == JOYSTICKCONTROL_PANEL_AXIS) {
      bool invert = false;
      if (event.IsChecked()) {
        invert = true;
      }
      if (joystickReaderThread->setAxisInversion(ident.joystickId, ident.id, invert) !=
          JOYSTICKCONTROL_OK)
      {
        dPrint(1, "Could not invert axis %d on joystick %d", ident.id, ident.joystickId);
      }
    }
  }
}
//*****************************************************************************

void JoystickControl::OnJoystickEvent(wxEvent &event)
{
  GIMUIJoystickEvent *jEvent;

  jEvent = dynamic_cast<GIMUIJoystickEvent*>(&event);
  assert(jEvent != NULL);
  
  //int joystickNumber = jEvent->getJoystickId();
  wxEventType eventType = jEvent->GetEventType();

  // Update gauges etc.
  t_joystickPanelsIterator jPanel = joystickPanels.find(jEvent->getJoystickId());
  if (jPanel != joystickPanels.end()) { // Panel found.
    if (eventType == wxEVT_GIMUI_JOYSTICK_MOVE) {
      jPanel->second.joystickAxes.setAxisPosition(jEvent->getChangeId(),
          jEvent->currentStatus.getPosition(jEvent->getChangeId()));
    } else if (eventType == wxEVT_GIMUI_JOYSTICK_BUTTON_UP) {
      jPanel->second.joystickButtons.setButtonPosition(jEvent->getChangeId(), false);
    } else if (eventType == wxEVT_GIMUI_JOYSTICK_BUTTON_DOWN) {
      jPanel->second.joystickButtons.setButtonPosition(jEvent->getChangeId(), true);
    } else {
      dPrint(1, "Got unknown event.");
    }
  }
  
  // Forward event
  components.forwardEvent(*jEvent);
  
  return;
}
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************

